import api from '../../api/index'
const app = getApp()

Page({
  data: {
    statusBarHeight: app.globalData.statusBarHeight,
    navBarHeight: app.globalData.navBarHeight,
    pcenterPageShow: false,
    idea: '',
    writingType: '',
    wordCount: '',
    outlineLevel: '',
    language: '',
    outlineContent: '',
    reasoningContent: '',
    generatingContent: '',
    generatingContentRaw: '', // 保存原始内容用于格式化
    fullTextContent: '',
    fullTextNodes: null as any,
    isGenerating: false,
    isGeneratingFullText: false,
    requestData: null,
    scrollIntoView: '',
    reasoningScrollIntoView: '', // reasoning-content区域的滚动控制
    fullTextScrollIntoView: '', // full-text-content区域的滚动控制
    currentParagraphIndex: 0,
    outlineTopics: [],
    completedParagraphs: [], // 保存已完成的段落内容（纯文本格式）
    fullTextCompleted: false, // 全文是否生成完成（用于控制UI）
    isIntegrating: false, // 是否正在整合论文
    postProcessCompleted: false, // 整合与格式变更是否完成
    // 论文格式选择
    showFormatSheet: false,
    selectedFormat: 'gbt7714',
    formatActions: [
      { name: 'gbt7714' },
      { name: 'apa' },
      { name: 'mla' },
      { name: 'chicago' },
      { name: 'harvard' },
      { name: 'ieee' }
    ],
    // 保存全文相关
    createdFileId: '',
    createdFileName: '空白文档',
    mainTitle: '',
    pageTitle: '论文大纲', // 页面标题，默认为"论文大纲"
    isSaved: false,
    isSaving: false
  },

  onLoad(options) {
    // 从页面参数中获取数据
    const { idea, writingType, wordCount, outlineLevel, language, requestData } = options
    this.setData({
      idea: decodeURIComponent(idea || ''),
      writingType: decodeURIComponent(writingType || ''),
      wordCount: decodeURIComponent(wordCount || ''),
      outlineLevel: decodeURIComponent(outlineLevel || ''),
      language: decodeURIComponent(language || ''),
      requestData: requestData ? JSON.parse(decodeURIComponent(requestData)) : null
    })
    
    // 启用分享功能
    wx.showShareMenu({
      withShareTicket: true,
      menus: ['shareAppMessage', 'shareTimeline']
    })
    
    // 延迟一点开始生成大纲，确保页面渲染完成
    setTimeout(() => {
      this.generateOutline()
    }, 100)
  },

    // 显示个人中心页面
    showPcenterPage() {
        this.setData({
          pcenterPageShow: true
        });
      },

     // 关闭个人中心页面
     closePcenterPage() {
       this.setData({
         pcenterPageShow: false
       });
     },

     // 返回上一页
     handleGoBack() {
         wx.navigateBack()
     },

  // 生成大纲
  async generateOutline() {
    if (!this.data.requestData) {
      wx.showToast({
        title: '参数错误',
        icon: 'error'
      })
      return
    }

    this.setData({
      isGenerating: true,
      outlineContent: '',
      reasoningContent: '',
      generatingContent: '',
      generatingContentRaw: '',
      // 重置保存相关状态
      createdFileId: this.data.createdFileId || '',
      isSaved: false,
      mainTitle: ''
    })

    try {
      const requestData = this.data.requestData
      // 并行启动：创建空白文档（用于后续保存全文）
      try {
        const noteRes: any = await api.createNote({ uid: 430, file_name: this.data.createdFileName || '空白文档' })
        if (noteRes && noteRes.status === 'success' && noteRes.data && noteRes.data.id) {
          this.setData({ createdFileId: noteRes.data.id, createdFileName: noteRes.data.file_name || '空白文档' })
        }
      } catch (e) {
        console.warn('创建笔记失败（不影响后续生成）：', e)
      }
      let apiUrl = ''

      // 根据写作类型确定API URL
      switch(requestData.category) {
        case 'freedom':
          apiUrl = '/aispire/file_write/writing_outline'
          break
        case 'literature':
          apiUrl = '/aispire/file_write/writing_literature_review_outline'
          break
        case 'paper':
          apiUrl = '/aispire/file_write/writing_academic_outline'
          break
        default:
          throw new Error('未知的写作类型')
      }

      // 使用流式API
      api.generateOutlineStream(apiUrl, requestData, {
        onData: (content, fieldType) => {
          if (fieldType === 'reasoning') {
            const newContent = this.data.reasoningContent + content
            this.setData({
              reasoningContent: newContent,
              reasoningScrollIntoView: 'reasoning-bottom' // 自动滚动到底部
              // 保持 isGenerating: true，直到流式请求完成
            }, () => {
              // 延迟清空scrollIntoView以便下次可以再次触发
              setTimeout(() => {
                this.setData({
                  reasoningScrollIntoView: ''
                })
              }, 100)
            })
          } else if (fieldType === 'generating') {
            // 先累加原始内容
            const rawContent = (this.data.generatingContentRaw || '') + content
            // 对整个内容进行格式化处理
            const processedContent = this.processGeneratingContent(rawContent)
            this.setData({
              generatingContentRaw: rawContent, // 保存原始内容
              generatingContent: processedContent // 保存格式化后的内容
              // 保持 isGenerating: true，直到流式请求完成
            }, () => {
              // 定位到正文生成区域，后续跟随内容滚动
              this.scrollToAreaAndFollow('generating-anchor', rawContent.length > 100)
            })
            // 更新一级标题：优先取更长且更完整的标题（流式过程中可能先到部分字符）
            const mt = this.extractMainTitleFromRaw(rawContent)
            if (mt && mt.length > (this.data.mainTitle ? this.data.mainTitle.length : 0)) {
              this.setData({ 
                mainTitle: mt,
                pageTitle: mt, // 同步更新页面标题
                createdFileName: mt // 同步更新文件名
              })
            }
          } else {
            // 兼容旧版本，直接添加到outlineContent
            this.setData({
              outlineContent: this.data.outlineContent + content
              // 保持 isGenerating: true，直到流式请求完成
            }, () => {
              this.scrollToBottom()
            })
          }
        },
        onError: (error) => {
          console.error('流式API错误:', error)
          this.setData({
            isGenerating: false
          })
          wx.showToast({
            title: error || '生成大纲失败',
            icon: 'error'
          })
        },
        onComplete: () => {
          this.setData({
            isGenerating: false
          })
          // 流式完成后再兜底提取一次完整的一级标题
          const finalMt = this.extractMainTitleFromRaw(this.data.generatingContentRaw || '')
          if (finalMt && finalMt.length > (this.data.mainTitle ? this.data.mainTitle.length : 0)) {
            this.setData({ 
              mainTitle: finalMt,
              pageTitle: finalMt, // 同步更新页面标题
              createdFileName: finalMt // 同步更新文件名
            })
          }
        }
      })
    } catch (error) {
      console.error('生成大纲异常:', error)
      this.setData({
        isGenerating: false
      })
      wx.showToast({
        title: '生成大纲失败',
        icon: 'error'
      })
    }
  },

  // 从原始大纲中提取一级标题（第一条以# 开头且非##/###）
  extractMainTitleFromRaw(raw: string): string {
    if (!raw) return ''
    const text = raw.replace(/<br\s*\/?\>/gi, '\n').replace(/<[^>]*>/g, '')
    const lines = text.split('\n')
    for (const l of lines) {
      const t = l.trim()
      if (/^#\s+/.test(t) && !/^##\s+/.test(t) && !/^###\s+/.test(t)) {
        return t.replace(/^#\s+/, '').trim()
      }
    }
    return ''
  },


  // 处理全文内容，格式化为 markdown 格式（包含所有内容）
  processFullTextContent(content: string) {
    if (!content) return ''
    
    let processedContent = content
    
    // 移除结束标记
    processedContent = processedContent.replace(/<\|EOS\|>/g, '')
    
    // 先将所有 <br/> 转换为换行符，便于处理
    processedContent = processedContent.replace(/<br\s*\/?>/gi, '\n')
    
    // 处理 LaTeX 数学公式（行内公式 $...$ 和块级公式 $$...$$）
    // 使用本地渲染：将 LaTeX 代码转换为可读的数学表达式文本
    const formulaMap = new Map<string, string>()
    let formulaIndex = 0
    
    // 将 LaTeX 转换为可显示的文本
    const convertLatexToDisplay = (latex: string): string => {
      if (!latex || typeof latex !== 'string') {
        return ''
      }
      
      let text = latex
        
      // 处理括号命令（需要先处理，避免被后续处理破坏）
      text = text.replace(/\\left\(/g, '(')
      text = text.replace(/\\right\)/g, ')')
      text = text.replace(/\\left\[/g, '[')
      text = text.replace(/\\right\]/g, ']')
      text = text.replace(/\\left\{/g, '{')
      text = text.replace(/\\right\}/g, '}')
      text = text.replace(/\\left\|/g, '|')
      text = text.replace(/\\right\|/g, '|')
      text = text.replace(/\\left\./g, '')
      text = text.replace(/\\right\./g, '')
      text = text.replace(/\\left/g, '(')
      text = text.replace(/\\right/g, ')')
      
      // 处理常用数学符号和命令
      text = text.replace(/\\mathbf\{([^}]+)\}/g, '<strong>$1</strong>') // 粗体
      text = text.replace(/\\mathcal\{([^}]+)\}/g, '$1') // 花体
      text = text.replace(/\\mathbb\{([^}]+)\}/g, '$1') // 黑板粗体
      text = text.replace(/\\text\{([^}]+)\}/g, '$1') // 文本
      text = text.replace(/\\boldsymbol\{([^}]+)\}/g, '<strong>$1</strong>') // 粗体符号
      
      // 处理函数名（需要先处理，避免被替换）
      text = text.replace(/\\log(?![a-zA-Z])/g, 'log')
      text = text.replace(/\\ln(?![a-zA-Z])/g, 'ln')
      text = text.replace(/\\exp(?![a-zA-Z])/g, 'exp')
      text = text.replace(/\\sin(?![a-zA-Z])/g, 'sin')
      text = text.replace(/\\cos(?![a-zA-Z])/g, 'cos')
      text = text.replace(/\\tan(?![a-zA-Z])/g, 'tan')
      text = text.replace(/\\sec(?![a-zA-Z])/g, 'sec')
      text = text.replace(/\\csc(?![a-zA-Z])/g, 'csc')
      text = text.replace(/\\cot(?![a-zA-Z])/g, 'cot')
      text = text.replace(/\\arcsin(?![a-zA-Z])/g, 'arcsin')
      text = text.replace(/\\arccos(?![a-zA-Z])/g, 'arccos')
      text = text.replace(/\\arctan(?![a-zA-Z])/g, 'arctan')
      text = text.replace(/\\max(?![a-zA-Z])/g, 'max')
      text = text.replace(/\\min(?![a-zA-Z])/g, 'min')
      text = text.replace(/\\sup(?![a-zA-Z])/g, 'sup')
      text = text.replace(/\\inf(?![a-zA-Z])/g, 'inf')
      text = text.replace(/\\lim(?![a-zA-Z])/g, 'lim')
      text = text.replace(/\\det(?![a-zA-Z])/g, 'det')
      text = text.replace(/\\dim(?![a-zA-Z])/g, 'dim')
      text = text.replace(/\\ker(?![a-zA-Z])/g, 'ker')
      text = text.replace(/\\rank(?![a-zA-Z])/g, 'rank')
      text = text.replace(/\\trace(?![a-zA-Z])/g, 'tr')
      text = text.replace(/\\Pr(?![a-zA-Z])/g, 'Pr')
      text = text.replace(/\\arg(?![a-zA-Z])/g, 'arg')
      text = text.replace(/\\gcd(?![a-zA-Z])/g, 'gcd')
      text = text.replace(/\\lcm(?![a-zA-Z])/g, 'lcm')
      
      // 处理特殊函数
      text = text.replace(/\\softmax(?![a-zA-Z])/g, 'softmax')
      text = text.replace(/\\sigmoid(?![a-zA-Z])/g, 'sigmoid')
      text = text.replace(/\\relu(?![a-zA-Z])/g, 'ReLU')
      text = text.replace(/\\tanh(?![a-zA-Z])/g, 'tanh')
      
      // 处理希腊字母
      text = text.replace(/\\theta/g, 'θ')
      text = text.replace(/\\Theta/g, 'Θ')
      text = text.replace(/\\alpha/g, 'α')
      text = text.replace(/\\Alpha/g, 'Α')
      text = text.replace(/\\beta/g, 'β')
      text = text.replace(/\\Beta/g, 'Β')
      text = text.replace(/\\gamma/g, 'γ')
      text = text.replace(/\\Gamma/g, 'Γ')
      text = text.replace(/\\delta/g, 'δ')
      text = text.replace(/\\Delta/g, 'Δ')
      text = text.replace(/\\epsilon/g, 'ε')
      text = text.replace(/\\varepsilon/g, 'ε')
      text = text.replace(/\\Epsilon/g, 'Ε')
      text = text.replace(/\\pi/g, 'π')
      text = text.replace(/\\Pi/g, 'Π')
      text = text.replace(/\\sigma/g, 'σ')
      text = text.replace(/\\Sigma/g, 'Σ')
      text = text.replace(/\\lambda/g, 'λ')
      text = text.replace(/\\Lambda/g, 'Λ')
      text = text.replace(/\\mu/g, 'μ')
      text = text.replace(/\\Mu/g, 'Μ')
      text = text.replace(/\\varphi/g, 'φ')
      text = text.replace(/\\phi/g, 'φ')
      text = text.replace(/\\Phi/g, 'Φ')
      text = text.replace(/\\omega/g, 'ω')
      text = text.replace(/\\Omega/g, 'Ω')
      text = text.replace(/\\xi/g, 'ξ')
      text = text.replace(/\\Xi/g, 'Ξ')
      text = text.replace(/\\zeta/g, 'ζ')
      text = text.replace(/\\eta/g, 'η')
      text = text.replace(/\\kappa/g, 'κ')
      text = text.replace(/\\iota/g, 'ι')
      text = text.replace(/\\rho/g, 'ρ')
      text = text.replace(/\\tau/g, 'τ')
      text = text.replace(/\\upsilon/g, 'υ')
      text = text.replace(/\\chi/g, 'χ')
      text = text.replace(/\\psi/g, 'ψ')
      text = text.replace(/\\Psi/g, 'Ψ')
      
      // 处理数学运算符
      text = text.replace(/\\infty/g, '∞')
      text = text.replace(/\\sum/g, '∑')
      text = text.replace(/\\prod/g, '∏')
      text = text.replace(/\\int/g, '∫')
      text = text.replace(/\\oint/g, '∮')
      text = text.replace(/\\iint/g, '∬')
      text = text.replace(/\\iiint/g, '∭')
      text = text.replace(/\\partial/g, '∂')
      text = text.replace(/\\nabla/g, '∇')
      text = text.replace(/\\ell/g, 'ℓ')
      text = text.replace(/\\hbar/g, 'ℏ')
      text = text.replace(/\\Im/g, 'ℑ')
      text = text.replace(/\\Re/g, 'ℜ')
      
      // 处理根号（需要先处理带指数的）
      text = text.replace(/\\sqrt\[([^\]]+)\]\{([^}]+)\}/g, '$1√($2)')
      text = text.replace(/\\sqrt\{([^}]+)\}/g, '√($1)')
      
      // 处理上下标（需要先处理，因为分数可能包含上下标）
      // 先处理复杂上标 ^{...}
      const processSubSup = (str: string): string => {
        // 递归处理上下标中的复杂内容
        str = str.replace(/\^\{([^}]+)\}/g, (match, content) => {
          const processed = processSubSup(content) // 递归处理嵌套
          return `<sup>${processed}</sup>`
        })
        // 处理简单上标 ^x（排除已经处理过的）
        str = str.replace(/\^([a-zA-Z0-9_]+)(?![^<]*<\/sup>)/g, '<sup>$1</sup>')
        
        // 先处理复杂下标 _{...}
        str = str.replace(/_\{([^}]+)\}/g, (match, content) => {
          const processed = processSubSup(content) // 递归处理嵌套
          return `<sub>${processed}</sub>`
        })
        // 处理简单下标 _x（排除已经处理过的）
        str = str.replace(/_([a-zA-Z0-9]+)(?![^<]*<\/sub>)/g, '<sub>$1</sub>')
        
        return str
      }
      text = processSubSup(text)
      
      // 处理分数（在上下标之后处理，因为它包含大括号）
      text = text.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g, (match, num, den) => {
        // 再次处理分子和分母中的 LaTeX（但避免递归嵌套）
        num = num.replace(/\\mathbf\{([^}]+)\}/g, '<strong>$1</strong>')
        num = num.replace(/\\mathcal\{([^}]+)\}/g, '$1')
        num = num.replace(/\\mathbb\{([^}]+)\}/g, '$1')
        den = den.replace(/\\mathbf\{([^}]+)\}/g, '<strong>$1</strong>')
        den = den.replace(/\\mathcal\{([^}]+)\}/g, '$1')
        den = den.replace(/\\mathbb\{([^}]+)\}/g, '$1')
        return `<span style="display:inline-block;vertical-align:middle;font-size:1em;"><span style="display:block;font-size:0.75em;line-height:1.2;">${num}</span><span style="display:block;border-top:1px solid #333;font-size:0.75em;line-height:1.2;margin-top:2rpx;padding-top:2rpx;">${den}</span></span>`
      })
      
      // 处理运算符
      text = text.replace(/\\cdot/g, '·')
      text = text.replace(/\\times/g, '×')
      text = text.replace(/\\div/g, '÷')
      text = text.replace(/\\pm/g, '±')
      text = text.replace(/\\mp/g, '∓')
      text = text.replace(/\\ast/g, '∗')
      text = text.replace(/\\star/g, '★')
      text = text.replace(/\\circ/g, '∘')
      text = text.replace(/\\bullet/g, '•')
      text = text.replace(/\\oplus/g, '⊕')
      text = text.replace(/\\ominus/g, '⊖')
      text = text.replace(/\\otimes/g, '⊗')
      text = text.replace(/\\oslash/g, '⊘')
      text = text.replace(/\\odot/g, '⊙')
      
      // 处理关系符
      text = text.replace(/\\leq/g, '≤')
      text = text.replace(/\\geq/g, '≥')
      text = text.replace(/\\neq/g, '≠')
      text = text.replace(/\\approx/g, '≈')
      text = text.replace(/\\equiv/g, '≡')
      text = text.replace(/\\sim/g, '∼')
      text = text.replace(/\\propto/g, '∝')
      text = text.replace(/\\cong/g, '≅')
      text = text.replace(/\\simeq/g, '≃')
      text = text.replace(/\\prec/g, '≺')
      text = text.replace(/\\succ/g, '≻')
      text = text.replace(/\\preceq/g, '≼')
      text = text.replace(/\\succeq/g, '≽')
      text = text.replace(/\\ll/g, '≪')
      text = text.replace(/\\gg/g, '≫')
      text = text.replace(/\\asymp/g, '≍')
      
      // 处理集合符号
      text = text.replace(/\\in/g, '∈')
      text = text.replace(/\\notin/g, '∉')
      text = text.replace(/\\subset/g, '⊂')
      text = text.replace(/\\supset/g, '⊃')
      text = text.replace(/\\subseteq/g, '⊆')
      text = text.replace(/\\supseteq/g, '⊇')
      text = text.replace(/\\cup/g, '∪')
      text = text.replace(/\\cap/g, '∩')
      text = text.replace(/\\emptyset/g, '∅')
      text = text.replace(/\\varnothing/g, '∅')
      text = text.replace(/\\setminus/g, '∖')
      
      // 处理箭头
      text = text.replace(/\\vdash/g, '⊢')
      text = text.replace(/\\dashv/g, '⊣')
      text = text.replace(/\\rightarrow/g, '→')
      text = text.replace(/\\leftarrow/g, '←')
      text = text.replace(/\\Rightarrow/g, '⇒')
      text = text.replace(/\\Leftarrow/g, '⇐')
      text = text.replace(/\\leftrightarrow/g, '↔')
      text = text.replace(/\\Leftrightarrow/g, '⇔')
      text = text.replace(/\\mapsto/g, '↦')
      text = text.replace(/\\to/g, '→')
      text = text.replace(/\\gets/g, '←')
      text = text.replace(/\\longrightarrow/g, '⟶')
      text = text.replace(/\\longleftarrow/g, '⟵')
      
      // 处理逻辑符号
      text = text.replace(/\\forall/g, '∀')
      text = text.replace(/\\exists/g, '∃')
      text = text.replace(/\\nexists/g, '∄')
      text = text.replace(/\\land/g, '∧')
      text = text.replace(/\\lor/g, '∨')
      text = text.replace(/\\neg/g, '¬')
      text = text.replace(/\\lnot/g, '¬')
      text = text.replace(/\\top/g, '⊤')
      text = text.replace(/\\bot/g, '⊥')
      text = text.replace(/\\wedge/g, '∧')
      text = text.replace(/\\vee/g, '∨')
      
      // 处理修饰符
      text = text.replace(/\\hat\{([^}]+)\}/g, '^$1')
      text = text.replace(/\\check/g, 'ˇ')
      text = text.replace(/\\breve/g, '˘')
      text = text.replace(/\\acute/g, '´')
      text = text.replace(/\\grave/g, '`')
      text = text.replace(/\\tilde\{([^}]+)\}/g, '~$1')
      text = text.replace(/\\bar\{([^}]+)\}/g, '¯$1')
      text = text.replace(/\\vec\{([^}]+)\}/g, '→$1')
      text = text.replace(/\\dot\{([^}]+)\}/g, '·$1')
      text = text.replace(/\\ddot\{([^}]+)\}/g, '··$1')
      text = text.replace(/\\dddot/g, '⋯')
      text = text.replace(/\\overline\{([^}]+)\}/g, '<span style="text-decoration:overline;">$1</span>')
      text = text.replace(/\\underline\{([^}]+)\}/g, '<span style="text-decoration:underline;">$1</span>')
      
      // 处理特殊符号
      text = text.replace(/\\mathbb\{E\}/g, 'E')
      text = text.replace(/\\mathbb\{P\}/g, 'P')
      text = text.replace(/\\mathbb\{R\}/g, 'ℝ')
      text = text.replace(/\\mathbb\{N\}/g, 'ℕ')
      text = text.replace(/\\mathbb\{Z\}/g, 'ℤ')
      text = text.replace(/\\mathbb\{Q\}/g, 'ℚ')
      text = text.replace(/\\mathbb\{C\}/g, 'ℂ')
      
      // 处理空格
      text = text.replace(/\\,/g, ' ')
      text = text.replace(/\\;/g, ' ')
      text = text.replace(/\\:/g, ' ')
      text = text.replace(/\\!/g, '')
      text = text.replace(/\\quad/g, '    ')
      text = text.replace(/\\qquad/g, '        ')
      
      // 处理换行
      text = text.replace(/\\\\/g, '<br/>')
      text = text.replace(/\\newline/g, '<br/>')
      text = text.replace(/\\break/g, '<br/>')
      
      // 清理剩余的转义和大括号
      try {
        text = text.replace(/\{/g, '')
        text = text.replace(/\}/g, '')
        text = text.replace(/\\/g, '')
      } catch (e) {
        console.error('清理LaTeX符号失败:', e)
      }
      
      return text || latex // 如果处理失败，返回原始latex
    }
    
    // 匹配块级公式 $$...$$（优先处理）
    // 使用非贪婪匹配，并支持跨行匹配
    try {
      // 先处理块级公式（多行匹配）
      processedContent = processedContent.replace(/\$\$([\s\S]*?)\$\$/g, (match, formula) => {
        try {
          if (!formula || formula.trim().length === 0) {
            return match
          }
          
          const placeholder = `__LATEX_FORMULA_BLOCK_${formulaIndex}__`
          const displayText = convertLatexToDisplay(formula.trim())
          formulaMap.set(placeholder, `<div class="latex-display-block" style="text-align:center;margin:20rpx 0;padding:20rpx;background:#f5f5f5;border-radius:8rpx;font-family:'Courier New',monospace;font-size:26rpx;line-height:1.8;">${displayText}</div>`)
          formulaIndex++
          return placeholder
        } catch (e) {
          console.error('处理块级公式失败:', e)
          // 如果处理失败，返回原始公式，不要中断流程
          return match
        }
      })
    } catch (e) {
      console.error('匹配块级公式失败:', e)
    }
    
    // 匹配行内公式 $...$（排除已处理的块级公式标记）
    // 使用非贪婪匹配，但不跨行（避免匹配到块级公式）
    try {
      processedContent = processedContent.replace(/\$([^$\n\r]+?)\$/g, (match, formula) => {
        try {
          // 排除已处理的公式标记或空公式
          if (match.includes('__LATEX_FORMULA') || !formula || formula.trim().length === 0) {
            return match
          }
          
          // 排除块级公式的残留部分（以 $$ 开头）
          if (match.startsWith('$$') || match.endsWith('$$')) {
            return match
          }
          
          const placeholder = `__LATEX_FORMULA_INLINE_${formulaIndex}__`
          const displayText = convertLatexToDisplay(formula.trim())
          formulaMap.set(placeholder, `<span class="latex-display-inline" style="font-family:'Courier New',monospace;font-size:24rpx;padding:2rpx 6rpx;background:#f0f0f0;border-radius:4rpx;vertical-align:baseline;">${displayText}</span>`)
          formulaIndex++
          return placeholder
        } catch (e) {
          console.error('处理行内公式失败:', e)
          // 如果处理失败，返回原始公式，不要中断流程
          return match
        }
      })
    } catch (e) {
      console.error('匹配行内公式失败:', e)
    }
    
    // 处理加粗格式 **文本**
    processedContent = processedContent.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>')
    
    // 处理列表项
    processedContent = processedContent.replace(/^(\s{4,}|\t+)\*\s+([^\n]+)/gm, '<div class="markdown-list-item-indent">◦ $2</div>')
    processedContent = processedContent.replace(/^\*\s+([^\n]+)/gm, '<div class="markdown-list-item">• $1</div>')
    
    // 处理三级标题
    processedContent = processedContent.replace(/###\s+([^\n]+)/g, '<div class="markdown-h3">$1</div>')
    
    // 处理二级标题
    processedContent = processedContent.replace(/##\s+([^\n]+)/g, '<div class="markdown-h2">$1</div>')
    
    // 处理一级标题
    processedContent = processedContent.replace(/^#\s+([^\n]+)/gm, '<div class="markdown-h1">$1</div>')
    
    // 处理行内换行和多余空行
    processedContent = processedContent.replace(/\n\n+/g, '<br/><br/>')
    
    // 将剩余的单个换行符转换为 <br/>
    processedContent = processedContent.replace(/\n/g, '<br/>')
    
    // 清理多余的 <br/> 标签
    processedContent = processedContent.replace(/(<br\/>){3,}/g, '<br/><br/>')
    
    // 清理标题前后的 <br/> 标签
    processedContent = processedContent.replace(/<br\/>(<div class="markdown-h[1-3]">)/g, '$1')
    processedContent = processedContent.replace(/(<\/div>)<br\/>/g, '$1')
    
    // 恢复 LaTeX 公式
    try {
      formulaMap.forEach((formulaHtml, placeholder) => {
        try {
          processedContent = processedContent.replace(placeholder, formulaHtml)
        } catch (e) {
          console.error('恢复公式占位符失败:', placeholder, e)
          // 如果恢复失败，保留占位符，不要中断
        }
      })
    } catch (e) {
      console.error('恢复LaTeX公式失败:', e)
    }
    
    return processedContent
  },

  // 处理 generating 内容，格式化为 markdown 格式
  // 仅保留标题内容，过滤掉其他内容
  processGeneratingContent(content: string) {
    if (!content) return ''
    
    let processedContent = content
    
    // 移除结束标记
    processedContent = processedContent.replace(/<\|EOS\|>/g, '')
    
    // 先将所有 <br/> 转换为换行符，便于处理
    processedContent = processedContent.replace(/<br\s*\/?>/gi, '\n')
    
    // 提取所有标题行（只保留 # 开头的行）
    const lines = processedContent.split('\n')
    const titleLines: string[] = []
    
    for (const line of lines) {
      const trimmedLine = line.trim()
      // 匹配 #、##、### 开头的标题
      if (trimmedLine.match(/^#+\s+/)) {
        titleLines.push(trimmedLine)
      }
    }
    
    // 如果没有任何标题，返回空字符串
    if (titleLines.length === 0) {
      return ''
    }
    
    // 重新组合标题内容，用换行符连接
    processedContent = titleLines.join('\n')
    
    // 处理三级标题 ### 标题格式（优先处理，避免被二级标题匹配）
    processedContent = processedContent.replace(/###\s+([^\n]+)/g, '<div class="markdown-h3">$1</div>')
    
    // 处理二级标题 ## 标题格式
    processedContent = processedContent.replace(/##\s+([^\n]+)/g, '<div class="markdown-h2">$1</div>')
    
    // 处理一级标题 # 标题格式（最后处理，避免被二级标题匹配）
    processedContent = processedContent.replace(/^#\s+([^\n]+)/gm, '<div class="markdown-h1">$1</div>')
    
    // 将换行符转换为 <br/>，但标题之间只需要一个 <br/>
    processedContent = processedContent.replace(/\n/g, '<br/>')
    
    // 清理多余的 <br/> 标签（3个或更多连续 <br/> 保留为 1 个）
    processedContent = processedContent.replace(/(<br\/>){2,}/g, '<br/>')
    
    // 清理标题前后的 <br/> 标签，使格式更整洁
    processedContent = processedContent.replace(/<br\/>(<div class="markdown-h[1-3]">)/g, '$1')
    processedContent = processedContent.replace(/(<\/div>)<br\/>/g, '$1')
    
    return processedContent
  },

  // 滚动到底部
  scrollToBottom() {
    // 使用 scroll-into-view 滚动到底部
    this.setData({
      scrollIntoView: 'scroll-bottom'
    })
    
    // 延迟一点时间后清空 scrollIntoView，以便下次可以再次触发
    setTimeout(() => {
      this.setData({
        scrollIntoView: ''
      })
    }, 100)
  },

  // 滚动到指定区域
  scrollTo(id: string) {
    this.setData({
      scrollIntoView: id
    })
    setTimeout(() => {
      this.setData({ scrollIntoView: '' })
    }, 100)
  },

  // 滚动到区域并跟随内容
  scrollToAreaAndFollow(id: string, hasContent: boolean = false) {
    if (!hasContent) {
      // 第一次输出，定位到区域顶部
      this.setData({
        scrollIntoView: id
      })
      setTimeout(() => {
        this.setData({ scrollIntoView: '' })
      }, 100)
    } else {
      // 后续内容更新，根据不同的区域选择不同的滚动策略
      if (id === 'reasoning-anchor') {
        // 对于 reasoning 区域，不自动滚动，让用户手动控制滚动位置以便查看完整内容
        // 这样用户可以上下滚动查看整个 reasoning-content 区域的生成过程
        return
      } else {
        // 对于其他区域（generating），滚动到底部跟随内容
        this.scrollToBottom()
      }
    }
  },

  // 重新生成大纲
  regenerateOutline() {
    this.generateOutline()
  },

  // 生成全文
  async generateFullText() {
    // 如果正在生成大纲或全文，则不允许操作
    if (this.data.isGenerating || this.data.isGeneratingFullText) {
      return
    }

    // 解析大纲中的标题
    const outlineTopics = this.parseOutlineTopics()
    if (outlineTopics.length === 0) {
      wx.showToast({
        title: '无法解析大纲标题',
        icon: 'none'
      })
      return
    }

    this.setData({
      isGeneratingFullText: true,
      fullTextContent: '',
      reasoningContent: '', // 重置推理内容
      currentParagraphIndex: 0,
      outlineTopics: outlineTopics,
      completedParagraphs: [], // 保存已完成的段落内容（纯文本格式）
      fullTextCompleted: false,
      postProcessCompleted: false
    })

    try {
      // 逐个生成段落
      for (let i = 0; i < outlineTopics.length; i++) {
        try {
          await this.generateParagraph(i)
        } catch (error) {
          console.error(`生成第${i + 1}个段落失败:`, error)
          // 继续生成下一个段落
          this.setData({
            currentParagraphIndex: i + 1
          })
        }
      }
      
      // 检查是否有内容生成（检查 completedParagraphs 或 fullTextNodes）
      const hasContent = (this.data.completedParagraphs && this.data.completedParagraphs.length > 0) || 
                        (this.data.fullTextNodes && this.data.fullTextNodes.length > 0) ||
                        (this.data.fullTextContent && this.data.fullTextContent.trim() !== '')
      
      if (!hasContent) {
        wx.showToast({
          title: '生成段落失败，请稍后重试',
          icon: 'none'
        })
      }
    } catch (error) {
      console.error('生成全文失败:', error)
      let errorMessage = '生成全文失败'
      
      if (error.message) {
        errorMessage = error.message
      }
      
      wx.showToast({
        title: errorMessage,
        icon: 'error'
      })
    } finally {
      // 检查是否有内容生成（检查 completedParagraphs 或 fullTextNodes）
      const hasContent = (this.data.completedParagraphs && this.data.completedParagraphs.length > 0) || 
                        (this.data.fullTextNodes && this.data.fullTextNodes.length > 0) ||
                        (this.data.fullTextContent && this.data.fullTextContent.trim() !== '')
      
      // 如果有主标题，更新页面标题和文件名
      const mainTitle = this.data.mainTitle || ''
      const updateData: any = {
        isGeneratingFullText: false,
        fullTextCompleted: hasContent
      }
      
      if (mainTitle && mainTitle.trim()) {
        updateData.pageTitle = mainTitle
        updateData.createdFileName = mainTitle
      }
      
      this.setData(updateData)
    }
  },

  // 构建提交给整合接口的纯文本内容
  buildFinalBody(): string {
    const completedParagraphs = this.data.completedParagraphs || []
    if (completedParagraphs.length === 0) {
      const html = this.data.fullTextContent || ''
      return html.replace(/<br\s*\/?\>/gi, '\n').replace(/<[^>]*>/g, '').trim()
    }
    let body = ''
    completedParagraphs.forEach((p: { title: string, content: string }) => {
      const title = (p.title || '').trim()
      let content = (p.content || '').trim()
      // 去掉开头连续的 Markdown 标题行，避免与外层标题重复
      while (content.startsWith('#')) {
        const nl = content.indexOf('\n')
        if (nl === -1) { content = ''; break }
        content = content.slice(nl + 1).trim()
      }
      // 标题不加#号，直接使用标题文本
      if (title) body += `${title}\n`
      if (content) body += `${content}\n\n`
    })
    return body.trim()
  },

  // 显示论文格式选择
  showFormatSheet() {
    this.setData({ showFormatSheet: true })
  },

  // 关闭论文格式选择
  closeFormatSheet() {
    this.setData({ showFormatSheet: false })
  },

  // 选择论文格式
  selectFormat(e: any) {
    const { name } = e.detail || {}
    if (name) {
      this.setData({ selectedFormat: name })
    }
    this.closeFormatSheet()
  },

  // 整合论文并切换为保存
  async integratePaper() {
    if (!this.data.fullTextCompleted || this.data.isIntegrating) return
    const uid = 430
    const body = this.buildFinalBody()
    if (!body) {
      wx.showToast({ title: '暂无可整合内容', icon: 'none' })
      return
    }
    this.setData({ isIntegrating: true })
    try {
      const mergeRes: any = await api.mergePaperReferences({ body, uid })
      if (!mergeRes || mergeRes.status !== 'success') throw new Error('整合参考文献失败')
      const mergedBody: string = mergeRes.data || body

      const target_format = this.data.selectedFormat || 'gbt7714'
      const formatRes: any = await api.changeCitationFormat({ body: mergedBody, target_format, uid })
      if (!formatRes || formatRes.status !== 'success') throw new Error('引用格式转换失败')
      let finalBody: string = formatRes.data || mergedBody

      // 预处理：防止有序列表被解析，保留文本中的序号
      // 在点号前添加零宽空格，防止markdown解析器将其识别为有序列表
      finalBody = finalBody.replace(/^(\d+)\.\s+(.+)$/gm, (_, num, content) => {
        // 使用零宽空格（\u200B）在点号前，视觉上不可见但能阻止列表解析
        return `${num}\u200B. ${content}`
      })

      // 使用 towxml 渲染最终 markdown，适配真机公式
      const nodes = (getApp() as any).towxml(finalBody, 'markdown', { theme: 'answer' })
      this.setData({
        reasoningContent: '',
        generatingContent: '',
        generatingContentRaw: '',
        outlineContent: '',
        fullTextContent: finalBody, // 保存整合后的 markdown 文本用于保存接口
        fullTextNodes: nodes,
        completedParagraphs: [],
        postProcessCompleted: true,
        fullTextCompleted: true,
        fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
      }, () => {
        // 延迟清空scrollIntoView以便下次可以再次触发
        setTimeout(() => {
          this.setData({
            fullTextScrollIntoView: ''
          })
        }, 100)
      })
    } catch (e: any) {
      console.error('整合论文失败:', e)
      wx.showToast({ title: e?.message || '整合失败', icon: 'error' })
    } finally {
      this.setData({ isIntegrating: false })
    }
  },

  // 保存全文（占位实现）
  async saveFullText() {
    if (!this.data.createdFileId) {
      wx.showToast({ title: '未创建文档，稍后重试', icon: 'none' })
      return
    }
    const uid = 430
    const title = this.data.mainTitle || '未命名'
    const file_name = title
    
    // 获取保存内容：优先使用整合后的 fullTextContent（markdown格式），否则从 completedParagraphs 构建
    let content = this.data.fullTextContent || ''
    if (!content || content.trim() === '') {
      // 如果没有整合后的内容，从 completedParagraphs 构建
      if (this.data.completedParagraphs && this.data.completedParagraphs.length > 0) {
        content = this.buildFinalBody()
      }
    } else {
      // 如果使用的是整合后的 fullTextContent，去掉所有标题前的 # 号
      // 匹配行首的 # 号（可能有一个或多个空格）
      content = content.replace(/^(\s*)(#{1,6})\s+(.+)$/gm, '$1$3')
    }
    
    if (!content || content.trim() === '') {
      wx.showToast({ title: '没有可保存的内容', icon: 'none' })
      return
    }
    
    // 组合 outline 字符串
    const outlineStr = this.buildMarkdownOutline() || ''
    // 组合最简 current_paragraph（使用已完成段落的标题与内容）
    const currentParagraph = (this.data.completedParagraphs || []).map((p: any) => ({ label: p.title, content: p.content }))
    this.setData({ isSaving: true })
    try {
      console.log('保存全文参数:', { uid, file_id: this.data.createdFileId, title, file_name, contentLength: content.length })
      const res: any = await api.updateNotes({ 
        uid, 
        file_id: this.data.createdFileId, 
        title, 
        file_name, 
        content, 
        outline: JSON.stringify({ treeData: [], str: outlineStr, params: this.data.requestData || {} }), 
        current_paragraph: JSON.stringify(currentParagraph) 
      })
      console.log('保存全文接口返回:', res)
      
      if (res && res.status === 'success') {
        this.setData({ isSaved: true, createdFileName: file_name })
        wx.showToast({ title: '论文已保存', icon: 'success' })
      } else {
        const errorMsg = res?.message || res?.error || '保存失败'
        console.error('保存失败，接口返回:', res)
        throw new Error(errorMsg)
      }
    } catch (e: any) {
      console.error('保存全文失败:', e)
      const errorMsg = e?.message || e?.errMsg || '保存失败'
      wx.showToast({ title: errorMsg, icon: 'error' })
    } finally {
      this.setData({ isSaving: false })
    }
  },

  // 分享PDF（占位实现）
  sharePdf() {
    wx.showToast({ title: '分享PDF开发中', icon: 'none' })
  },

  // 构建用于显示的已完成段落内容
  buildDisplayContent() {
    const completedParagraphs = this.data.completedParagraphs || []
    if (completedParagraphs.length === 0) {
      return ''
    }
    
    let displayContent = ''
    completedParagraphs.forEach((paragraph: { title: string, content: string }) => {
      // 使用完整内容处理函数，显示所有内容
      const processedContent = this.processFullTextContent(paragraph.content)
      displayContent += processedContent + '<br/><br/>'
    })
    
    return displayContent
  },

  // 将已完成段落与当前段落（可选）拼成 markdown，用于 towxml 渲染
  buildMarkdownForDisplay(currentParagraph?: string) {
    const completedParagraphs = this.data.completedParagraphs || []
    let md = ''
    completedParagraphs.forEach((p: { title: string, content: string }) => {
      const title = (p.title || '').trim()
      let content = (p.content || '').trim()
      // 去掉内容开头连续的 Markdown 标题行，避免与外层标题重复
      while (content.startsWith('#')) {
        const nl = content.indexOf('\n')
        if (nl === -1) { content = ''; break }
        content = content.slice(nl + 1).trim()
      }
      if (title) md += `# ${title}\n`
      if (content) md += `${content}\n\n`
    })
    if (currentParagraph) {
      // 同样去掉当前段落开头的标题行，避免重复标题
      let cp = currentParagraph
      while (cp.startsWith('#')) {
        const nl = cp.indexOf('\n')
        if (nl === -1) { cp = ''; break }
        cp = cp.slice(nl + 1).trim()
      }
      md += `${cp}`
    }
    return md
  },

  // 从已完成的段落构建 context
  buildContextFromCompletedParagraphs(currentIndex: number) {
    const completedParagraphs = this.data.completedParagraphs || []
    if (completedParagraphs.length === 0) {
      return ' '
    }
    
    // 格式化为 " \n# 标题\n段落内容 \n"
    let context = ' \n'
    completedParagraphs.forEach((paragraph: { title: string, content: string }) => {
      context += `# ${paragraph.title}\n${paragraph.content} \n`
    })
    
    return context
  },

  // 构建 markdown 格式的大纲（只包含 # 和 ## 标题）
  buildMarkdownOutline() {
    let content = this.data.generatingContentRaw || this.data.generatingContent
    content = content.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]*>/g, '')
    content = content.replace(/<\|EOS\|>/g, '')
    
    const lines = content.split('\n')
    const outlineLines: string[] = []
    
    for (const line of lines) {
      const trimmedLine = line.trim()
      // 保留一级标题和二级标题
      if (trimmedLine.match(/^##?\s+/) && !trimmedLine.match(/^###/)) {
        outlineLines.push(trimmedLine)
      }
    }
    
    return outlineLines.join('\n')
  },

  // 解析大纲中的标题
  parseOutlineTopics() {
    const topics: string[] = []
    
    // 使用原始内容进行解析（generatingContentRaw），因为格式化后的内容已经移除了 # 符号
    let content = this.data.generatingContentRaw || this.data.generatingContent
    
    // 如果没有原始内容，尝试从格式化后的内容中提取
    if (!this.data.generatingContentRaw && this.data.generatingContent) {
      // 从格式化后的 HTML 中提取二级标题文本
      const h2Matches = this.data.generatingContent.match(/<div class="markdown-h2">([^<]+)<\/div>/g)
      if (h2Matches && h2Matches.length > 0) {
        h2Matches.forEach(match => {
          const title = match.replace(/<[^>]*>/g, '').trim()
          if (title && !title.includes('<|EOS|>')) {
            topics.push(title)
          }
        })
        return topics
      }
    }
    
    // 处理换行符，移除HTML标签
    let cleanContent = content.replace(/<br\s*\/?>/gi, '\n')
    cleanContent = cleanContent.replace(/<[^>]*>/g, '')
    
    // 移除结束标记
    cleanContent = cleanContent.replace(/<\|EOS\|>/g, '')
    
    // 按换行符分割
    const lines = cleanContent.split('\n')
    
    for (const line of lines) {
      const trimmedLine = line.trim()
      
      // 匹配二级标题 ## 开头的行
      if (trimmedLine.match(/^##\s+/) && !trimmedLine.match(/^###/)) {
        const title = trimmedLine.replace(/^##\s+/, '').trim()
        // 确保标题不包含其他标题标记
        if (title && !title.includes('<|EOS|>') && !title.includes('###') && !title.includes('##')) {
          topics.push(title)
        }
      }
    }
    
    return topics
  },

  // 生成单个段落
  async generateParagraph(index) {
    try {
      // 检查用户配额
      const quotaResult = await api.checkUserQuota({ uid: 430 })
      
      // 检查返回数据结构
      if (!quotaResult) {
        console.error('配额检查返回为空')
        throw new Error('配额检查失败')
      }
      
      // 检查配额状态
      if (quotaResult.status !== 'success') {
        console.error('用户配额不足:', quotaResult)
        throw new Error('用户配额不足')
      }

      // 准备请求数据
      const topic = this.data.outlineTopics[index]
      // 从已完成的段落构建 context，格式为 " \n# 标题\n段落内容"
      const context = this.buildContextFromCompletedParagraphs(index)
      // 从原始内容构建 markdown 格式的大纲，只保留 # 和 ## 标题
      const outline = this.buildMarkdownOutline()
      
      // 分支：文献综述 vs 普通段落
      const isLiterature = (this.data.writingType === '文献综述') || (this.data.requestData && this.data.requestData.category === 'literature')

      // 使用流式API生成段落
      // 开始生成新段落时，清空当前段落的 reasoning 内容
      let paragraphReasoningContent = ''
      let paragraphGeneratingContent = ''
      this.setData({
        reasoningContent: '' // 清空之前的 reasoning，只显示当前段落的
      })

      if (isLiterature) {
        const literatureReq = {
          uid: 430,
          category: 'literature',
          idea: this.data.idea,
          dir_id: (this.data.requestData && this.data.requestData.dir_id) || '',
          type: (this.data.requestData && this.data.requestData.type) || 'short',
          style: 'timeline',
          level: (this.data.requestData && this.data.requestData.level) || 1,
          language: (this.data.requestData && this.data.requestData.language) || (this.data.language === '中文' ? 'zh' : (this.data.language === '英文' ? 'en' : 'zh'))
        }

        await new Promise<void>((resolve, reject) => {
          api.generateOutlineStream('/aispire/file_write/writing_literature_review_paragraph', literatureReq, {
            onData: (content, fieldType) => {
              if (fieldType === 'reasoning') {
                paragraphReasoningContent += content
                this.setData({
                  reasoningContent: paragraphReasoningContent,
                  reasoningScrollIntoView: 'reasoning-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      reasoningScrollIntoView: ''
                    })
                  }, 100)
                })
              } else if (fieldType === 'generating') {
                paragraphGeneratingContent += content
                // 使用 markdown + towxml 渲染，适配真机公式
                const markdown = this.buildMarkdownForDisplay(paragraphGeneratingContent)
                const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
                this.setData({ 
                  fullTextNodes: nodes,
                  fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      fullTextScrollIntoView: ''
                    })
                  }, 100)
                })
              } else {
                // 兼容旧版本，直接累加
                paragraphGeneratingContent += content
                const markdown = this.buildMarkdownForDisplay(paragraphGeneratingContent)
                const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
                this.setData({ 
                  fullTextNodes: nodes,
                  fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      fullTextScrollIntoView: ''
                    })
                  }, 100)
                })
              }
            },
            onError: (error) => {
              console.error('生成段落流式错误:', error)
              reject(new Error(error))
            },
            onComplete: () => {
              // 保存已完成的段落内容（纯文本格式，用于 context）
              const cleanParagraph = paragraphGeneratingContent.replace(/<[^>]*>/g, '').replace(/<br\s*\/?>/gi, '\n').trim()
              const topic = this.data.outlineTopics[index]
              const completedParagraphs = this.data.completedParagraphs || []
              completedParagraphs.push({
                title: topic,
                content: cleanParagraph
              })
              
              // 更新 fullTextContent 为最终格式（已完成的段落 + 当前刚完成的段落）
              const markdown = this.buildMarkdownForDisplay()
              const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
              this.setData({ 
                fullTextNodes: nodes, 
                completedParagraphs: completedParagraphs,
                fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
              }, () => {
                // 延迟清空scrollIntoView以便下次可以再次触发
                setTimeout(() => {
                  this.setData({
                    fullTextScrollIntoView: ''
                  })
                }, 100)
              })
              
              resolve()
            }
          })
        })
      } else {
        const requestData = {
          uid: 430,
          outline: outline,
          topic: topic,
          context: context,
          knowledge_base: [],
          language: this.data.language === '中文' ? 'zh' : (this.data.language === '英文' ? 'en' : 'zh'),
          dir_id: ""
        }

        await new Promise<void>((resolve, reject) => {
          api.generateOutlineStream('/aispire/file_write/writing_paragraph', requestData, {
            onData: (content, fieldType) => {
              if (fieldType === 'reasoning') {
                paragraphReasoningContent += content
                this.setData({
                  reasoningContent: paragraphReasoningContent,
                  reasoningScrollIntoView: 'reasoning-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      reasoningScrollIntoView: ''
                    })
                  }, 100)
                })
              } else if (fieldType === 'generating') {
                paragraphGeneratingContent += content
                const markdown = this.buildMarkdownForDisplay(paragraphGeneratingContent)
                const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
                this.setData({ 
                  fullTextNodes: nodes,
                  fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      fullTextScrollIntoView: ''
                    })
                  }, 100)
                })
              } else {
                // 兼容旧版本，直接累加
                paragraphGeneratingContent += content
                const markdown = this.buildMarkdownForDisplay(paragraphGeneratingContent)
                const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
                this.setData({ 
                  fullTextNodes: nodes,
                  fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
                }, () => { 
                  // 延迟清空scrollIntoView以便下次可以再次触发
                  setTimeout(() => {
                    this.setData({
                      fullTextScrollIntoView: ''
                    })
                  }, 100)
                })
              }
            },
            onError: (error) => {
              console.error('生成段落流式错误:', error)
              reject(new Error(error))
            },
            onComplete: () => {
              // 保存已完成的段落内容（纯文本格式，用于 context）
              const cleanParagraph = paragraphGeneratingContent.replace(/<[^>]*>/g, '').replace(/<br\s*\/?>/gi, '\n').trim()
              const topic = this.data.outlineTopics[index]
              const completedParagraphs = this.data.completedParagraphs || []
              completedParagraphs.push({
                title: topic,
                content: cleanParagraph
              })
              
              // 更新 fullTextContent 为最终格式（已完成的段落 + 当前刚完成的段落）
              const markdown = this.buildMarkdownForDisplay()
              const nodes = (getApp() as any).towxml(markdown, 'markdown', { theme: 'answer' })
              this.setData({ 
                fullTextNodes: nodes, 
                completedParagraphs: completedParagraphs,
                fullTextScrollIntoView: 'full-text-bottom' // 自动滚动到底部
              }, () => {
                // 延迟清空scrollIntoView以便下次可以再次触发
                setTimeout(() => {
                  this.setData({
                    fullTextScrollIntoView: ''
                  })
                }, 100)
              })
              
              resolve()
            }
          })
        })
      }
     } catch (error) {
       console.error('生成段落失败:', error)
       throw error
     }
  },

  // 继续写作
  continueWriting() {
    // TODO: 跳转到写作页面
    wx.showToast({
      title: '功能开发中',
      icon: 'none'
    })
  },

  // 返回上一页
  goBack() {
    wx.navigateBack()
  },

  // 分享页面
  onShareAppMessage() {
    const { idea, writingType, wordCount, outlineLevel, language, requestData, mainTitle, createdFileId } = this.data
    
    // 构建分享路径，包含必要的参数
    let sharePath = `/pages/outline-display/outline-display`
    const params: string[] = []
    
    if (idea) params.push(`idea=${encodeURIComponent(idea)}`)
    if (writingType) params.push(`writingType=${encodeURIComponent(writingType)}`)
    if (wordCount) params.push(`wordCount=${encodeURIComponent(wordCount)}`)
    if (outlineLevel) params.push(`outlineLevel=${encodeURIComponent(outlineLevel)}`)
    if (language) params.push(`language=${encodeURIComponent(language)}`)
    if (requestData) params.push(`requestData=${encodeURIComponent(JSON.stringify(requestData))}`)
    if (createdFileId) params.push(`fileId=${encodeURIComponent(createdFileId)}`)
    
    if (params.length > 0) {
      sharePath += `?${params.join('&')}`
    }
    
    // 构建分享标题
    const shareTitle = mainTitle 
      ? `论文：${mainTitle}`
      : (idea ? `论文大纲：${idea.substring(0, 20)}${idea.length > 20 ? '...' : ''}` : '论文大纲')
    
    return {
      title: shareTitle,
      desc: idea ? `基于"${idea.substring(0, 50)}${idea.length > 50 ? '...' : ''}"生成的论文` : '查看论文大纲',
      path: sharePath,
      imageUrl: '' // 可以设置分享图片URL
    }
  }
})
